﻿import { Component, OnInit } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { forkJoin } from 'rxjs';
import { finalize } from 'rxjs/operators';
import { NzModalService } from 'ng-zorro-antd/modal';
import { NzDrawerService } from 'ng-zorro-antd/drawer';
import { NzMessageService } from 'ng-zorro-antd/message';
import { ListService, LocalizationService, TrackByService } from '@abp/ng.core';
import { SearchDropdownMenuItem } from 'joy-abpui-angular';
import { AdvancedFilterDialogComponent } from '../../core/advanced-filter-dialog/advanced-filter-dialog.component';
import { TableSettingsDialogComponent } from '../../core/table-settings-dialog/table-settings-dialog.component';
import { FilterGroupDto } from '../../proxy/joy/erp/basic-archives/core/filters/models';
import { FilterGroupRequestDto } from '../../proxy/joy/erp/basic-archives/core/filters';
import { {{class_name}}Dto, {{class_name}}Service } from '../../proxy/joy/erp/{{to_kebab_case(project_group_name)}}/{{to_kebab_case(parent_menu)}}';
import { {{class_name}}DawEntityComponent } from '../{{to_kebab_case(class_name)}}-daw-entity/{{to_kebab_case(class_name)}}-daw-entity.component';
import * as XLSX from 'xlsx';
import { debounce } from '../../core/debounce.util';

@Component({
  selector: 'lib-{{to_kebab_case(class_name)}}-list',
  templateUrl: './{{to_kebab_case(class_name)}}-list.component.html',
  styleUrls: ['./{{to_kebab_case(class_name)}}-list.component.less'],
  providers: [ListService],
})
export class {{class_name}}ListComponent implements OnInit {
  entityConfig = {
    entityType: '{{namespace}}.{{class_name}}',
    propertys: [
      {
        name: 'Code',
        key: 'code',
        type: 'string',
        width: 200,
        show: true
      },      
      {{~ for property in exclude_propertys(self_value_propertys, "TenantId", "Level", "ParentId") ~}}      
      {
        name: '{{property.name}}',
        key: '{{to_camel_case(property.name)}}',
        type: '{{to_dto_declare_text(property.property_type)}}',
        width: 200,
        show: true
      },
      {{~ end ~}}
      {
        name: 'CreationTime',
        key: 'creationTime',
        type: 'date',
        width: 200,
        show: true
      },
    ]
  };

  models: {{class_name}}Dto[] = [];
  selectedModels: {{class_name}}Dto[] = [];
  totalCount: number = 0;
  filter: string = '';
  currentFilterGroup: FilterGroupDto = null;
  searchDropdownMenuItems: SearchDropdownMenuItem[] = [
    { itemDisplayName: this.l('BasicArchives::UI:AdvancedFilterDialog.Title'), fn: this.showAdvancedSearch.bind(this) }, 
    { itemDisplayName: this.l('BasicArchives::UI:TableSettings.Title'), fn: this.showTableSettings.bind(this) }
  ];

  public get currentPage() {
    return this.listService.page + 1;
  }

  public set currentPage(page: number) {
    this.listService.page = Math.max(page - 1, 0);
  }

  public get maxResultCount() {
    return this.listService.maxResultCount;
  }

  public set maxResultCount(value: number) {
    this.listService.maxResultCount = value;
  }

  public get pageCount(): number {
    if (this.totalCount <= 0 || this.listService.maxResultCount <= 0) return 0;
    const pageCount = Math.floor(this.totalCount / this.listService.maxResultCount);
    return this.totalCount % this.listService.maxResultCount == 0 ? pageCount : pageCount + 1;
  }

  public get isAllSelected(): boolean {
    return (
      this.models.every(model => this.selectedModels.some(item => item.id === model.id)) &&
      !!this.models?.length
    );
  }
  public get indeterminate(): boolean {
    return (
      this.models.some(model => this.selectedModels.some(item => item.id == model.id)) &&
      !this.models.every(model => this.selectedModels.some(item => item.id == model.id))
    );
  }
  public get selectedCount(): number {
    return !!this.selectedModels.length ? this.selectedModels.length : 0;
  }

  isDeleteButtonDisabledFn = () => this.selectedCount <= 0;

  constructor(
    public router: Router,
    public route: ActivatedRoute,
    public readonly track: TrackByService,
    public readonly listService: ListService<FilterGroupRequestDto>,
    public drawerService: NzDrawerService,
    public modalService: NzModalService,
    public message: NzMessageService,
    public localizationService: LocalizationService,
    public entityService: {{class_name}}Service,
  ) {  }

  ngOnInit(): void {
    this.loadTableSettings(); // 加载保存的配置
    this.listService.maxResultCount = 10;
    this.listService
      .hookToQuery(query => this.getListData(query))
      .subscribe(listResult => this.renderModels(listResult));
  }

  renderModels(listResult) {    
    this.clearSelect();
    this.models = listResult.items;
    this.totalCount = listResult.totalCount;
  }

  isModelSelected(model: {{class_name}}Dto): boolean {
    if (!this.selectedModels?.length) return false;
    if (this.selectedModels.length <= 0) return false;
    return !!this.selectedModels.find(x => x.id == model.id);
  }

  targetModelSelect(model: {{class_name}}Dto): void {
    if (!this.selectedModels.some(item => item.id === model.id)) {
      this.selectedModels = [...this.selectedModels, model];
    } else {
      this.selectedModels = [...this.selectedModels.filter(item => item.id !== model.id)];
    }
  }

  targetAllSelect() {
    const allselected = this.models.every(model =>
      this.selectedModels.some(item => item.id === model.id)
    );

    if (allselected) {
      this.selectedModels = [
        ...this.selectedModels.filter(item => !this.models.some(model => model.id === item.id)),
      ];
    } else {
      this.selectedModels = [
        ...this.selectedModels,
        ...this.models.filter(model => !this.selectedModels.some(item => model.id === item.id)),
      ];
    }
  }

  clearSelect() {
    this.selectedModels = [];
  }

  new() {
    const drawerRef = this.drawerService.create<UnitDawEntityComponent, { value: string }, string>({
      nzTitle: this.l('BasicArchives::Menu:{{project_group_name}}.{{parent_menu}}.{{class_name}}'),
      nzContent: UnitDawEntityComponent,
      nzWidth: window.innerWidth * 0.7,
      nzContentParams: {
        value: ""
      },
    });

    drawerRef.afterClose.subscribe(_ => {
      this.listService.get();
    });
  }

  delete() {
    if (this.selectedModels.length <= 0) return;

    this.modalService.confirm({
      nzTitle: this.l('BasicArchives::UI:Confirm.Title.Tips'),
      nzContent: this.l('BasicArchives::UI:Confirm.Content.DeleteConfirm'),
      nzOkText: this.l('BasicArchives::UI:Confirm.Button.OK'),
      nzCancelText: this.l('BasicArchives::UI:Confirm.Button.Cancel'),
      nzOnOk: () => {
        forkJoin(
          this.selectedModels.map(model => 
            this.entityService.delete(model.id)
          )
        ).pipe(
          finalize(() => {
            this.message.success(this.l('BasicArchives::UI:Message.DeleteSuccess'));
            this.clearSelect();
            this.listService.get();
          })
        ).subscribe();
      }
    });
  }

  refresh() {
    this.listService.get();
  }

  @debounce(300)
  view(model: {{class_name}}Dto, event?: Event) {
    event?.stopPropagation();
    
    const drawerRef = this.drawerService.create<{{class_name}}DawEntityComponent>({
      nzTitle: this.l('BasicArchives::Menu:{{project_group_name}}.{{parent_menu}}.{{class_name}}'),
      nzContent: {{class_name}}DawEntityComponent,
      nzWidth: window.innerWidth * 0.7,
      nzContentParams: {
        id: model.id
      }
    });

    drawerRef.afterClose.subscribe(() => {
      this.listService.get();
    });
  }

  export() {
    if (!this.models || this.models.length === 0) {
      this.message.warning(this.l('BasicArchives::UI:ExportDialog.Message.NoData'));
      return;
    }

    this.modalService.confirm({
      nzTitle: this.l('BasicArchives::UI:ExportDialog.Title'),
      nzContent: this.l('BasicArchives::UI:ExportDialog.Content'),
      nzOkText: this.l('BasicArchives::UI:ExportDialog.OK'),
      nzCancelText: this.l('BasicArchives::UI:ExportDialog.Cancel'),
      nzOnOk: () => {
        const visibleColumns = this.entityConfig.propertys.filter(prop => prop.show);

        const exportData = this.models.map(item => {
          const rowData = {};
          visibleColumns.forEach(prop => {
            const columnName = this.l(`BasicArchives::ModelTitle:${this.entityConfig.entityType}.${prop.name}`);
            
            let value = item[prop.key];
            if (prop.type === 'date' && value) {
              const date = new Date(value);
              value = `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
            }
            
            rowData[columnName] = value;
          });
          return rowData;
        });

        const worksheet = XLSX.utils.json_to_sheet(exportData);
        const workbook = XLSX.utils.book_new();
        XLSX.utils.book_append_sheet(workbook, worksheet, this.l('BasicArchives::Menu:{{project_group_name}}.{{parent_menu}}.{{class_name}}'));

        const fileName = `${this.l('BasicArchives::Menu:{{project_group_name}}.{{parent_menu}}.{{class_name}}')}_${new Date().toISOString().split('T')[0]}.xlsx`;

        XLSX.writeFile(workbook, fileName);
      }
    });
  }
  
  search(filter: string) {
    this.filter = filter;
    this.currentFilterGroup = null;
    
    if (this.listService.page !== 0) {
      this.listService.page = 0;
    }
    
    this.clearSelect();
    this.listService.get();
  }

  showAdvancedSearch() {
    const modalRef = this.modalService.create({
      nzTitle: this.l('BasicArchives::UI:AdvancedFilterDialog.Title'),
      nzContent: AdvancedFilterDialogComponent,
      nzWidth: 880,
      nzFooter: null,
      nzMaskClosable: false,
      nzComponentParams: {
        entityConfig: this.entityConfig,
        filterGroup: this.currentFilterGroup
      }
    });

    modalRef.afterClose.subscribe((filterGroup: FilterGroupDto) => {
      if (filterGroup) {
        this.handleAdvancedSearchResult(filterGroup);
      }
    });
  }

  showTableSettings() {
    const modalRef = this.modalService.create({
      nzTitle: this.l('BasicArchives::UI:TableSettings.Title'),
      nzContent: TableSettingsDialogComponent,
      nzWidth: 600,
      nzFooter: null,
      nzComponentParams: {
        entityConfig: this.entityConfig
      }
    });

    modalRef.afterClose.subscribe((columns: any[]) => {
      if (columns) {
        this.entityConfig.propertys.forEach(prop => {
          const column = columns.find(c => c.name === prop.name);
          if (column) {
            prop.width = column.width;
            prop.show = column.show;
          }
        });

        this.saveTableSettings();
      }
    });
  }

  protected loadTableSettings() {
    const savedSettings = localStorage.getItem(`tableSettings::${this.entityConfig.entityType}`);
    if (savedSettings) {
      const settings = JSON.parse(savedSettings);

      this.entityConfig.propertys.forEach(prop => {
        const savedProp = settings.find(s => s.name === prop.name);
        if (savedProp) {
          prop.width = savedProp.width;
          prop.show = savedProp.show;
        }
      });
    }
  }

  protected saveTableSettings() {
    const settings = this.entityConfig.propertys.map(prop => ({
      name: prop.name,
      type: prop.type,
      width: prop.width,
      show: prop.show
    }));
    localStorage.setItem(`tableSettings::${this.entityConfig.entityType}`, JSON.stringify(settings));
  }

  protected getListData(query: any) {
    const baseParams = {
      maxResultCount: query.maxResultCount,
      skipCount: query.skipCount,
      sorting: query.sorting || 'CreationTime desc'
    };

    return this.filter 
      ? this.entityService.getList({
          ...baseParams,
          filter: this.filter
        })
      : this.entityService.query({
          ...baseParams,
          filterGroup: this.currentFilterGroup
        });
  }

  protected handleAdvancedSearchResult(filterGroup: FilterGroupDto) {
    this.currentFilterGroup = filterGroup;
    this.filter = '';
    
    if (this.listService.page !== 0) {
      this.listService.page = 0;
    }
    
    this.clearSelect();
    this.listService.get();
  }

  protected l(key: string, ...args: any[]): string {
    return this.localizationService.instant(key, ...args);
  }
}
